package com.michau.testitas.core.dao.hibernate;

import com.michau.testitas.core.dao.api.GenericDao;
import org.apache.commons.lang.ArrayUtils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * User: michau
 * Date: 3/2/13
 * Time: 1:25 PM
 */
@Repository
public class GenericDaoHibernate<T, PK extends Serializable> implements GenericDao<T, PK> {

    @Autowired
    private SessionFactory sessionFactory;

    private Class<T> clazz;

    protected Session getSession(){
        if (sessionFactory == null){
             throw new IllegalArgumentException("SessionFactory must be set by Hibernate!");
        }
        return SessionFactoryUtils.getSession(sessionFactory, true);
    }

    public GenericDaoHibernate (Class<T> clazz){
        this.clazz = clazz;
    }

    @Override
    public T getById(final PK id) {
        return (T) getSession().get(clazz, id);
    }

    @Override
    public Set<T> getByIds(Collection<PK> ids) {
        if (ids.isEmpty()){
            return Collections.emptySet();
        }
        return new HashSet<T>(getSession()
                .createCriteria(clazz)
                .add(Restrictions.in("id", ids))
                .list());
    }

    @Override
    public T create(T object) {
        getSession().save(object);
        return object;
    }

    @Override
    public T update(T object) {
        getSession().update(object);
        return object;
    }

    @Override
    public void delete(T... objects) {
        if (ArrayUtils.isEmpty(objects)){
            throw new IllegalArgumentException("At least one object to delete must be specified.");
        }
        Session session = getSession();
        for (T object : objects){
            session.delete(object);
        }
    }

    @Override
    public Set<T> getAll() {
        return new HashSet<T>(getSession().createCriteria(clazz).list());
    }

    @Override
    public void deleteAll() {
        if ((Long)getSession().createQuery("select count(*) from " + clazz.getSimpleName()).uniqueResult() > 0){
            getSession().createQuery("delete * from " + clazz.getSimpleName()).executeUpdate();
        }
    }

    @Override
    public T getByTransferKey(String transferKey) {
        if (StringUtils.hasText(transferKey)){
            return (T) getSession().createCriteria(clazz)
                    .add(Restrictions.eq("transferKey", transferKey)).uniqueResult();
        }
        return null;
    }
}
